package xaj.weavingtest.ast.istype;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import polyglot.types.SemanticException;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import soot.SootMethod;
import abc.weaving.aspectinfo.ArgPattern;
import abc.weaving.aspectinfo.DynamicValuePointcut;
import abc.weaving.matching.MatchingContext;
import abc.weaving.matching.ShadowMatch;
import abc.weaving.matching.WeavingEnv;
import abc.weaving.residues.AlwaysMatch;
import abc.weaving.residues.AndResidue;
import abc.weaving.residues.ContextValue;
import abc.weaving.residues.NeverMatch;
import abc.weaving.residues.Residue;
import abc.weaving.residues.WeavingVar;

import abc.weaving.aspectinfo.*;

/** Handler for <code>args</code> condition pointcut.
 *  @author Aske Simon Christensen
 *  @author Ganesh Sittampalam
 *  @author Damien Sereni
 */
public class Args_isType extends abc.weaving.aspectinfo.Args {

    public Args_isType(List args,Position pos) {
        super(args, pos);
    }

    public Pointcut inline(Hashtable renameEnv,
                              Hashtable typeEnv,
                              Aspect context,
			      int cflowdepth) {
    	List args = getArgs();
        Iterator it=args.iterator();
        List newargs=new LinkedList();
        while(it.hasNext()) {
            ArgPattern arg=(ArgPattern) it.next();
            // Ought to delegate this really, but this is easier
            if(arg instanceof ArgVar) {
                ArgVar argvar=(ArgVar) arg;
                newargs.add(new ArgVar(argvar.getVar().rename(renameEnv),
                                       argvar.getPosition()));
            } else newargs.add(arg);
        }
        return new Args_isType(newargs,getPosition());

    }

    public Residue matchesAt(MatchingContext mc)
        throws SemanticException
    {
        WeavingEnv we = mc.getWeavingEnv();
        SootMethod method = mc.getSootMethod();
        ShadowMatch sm = mc.getShadowMatch();
        List args = getArgs();
        if(abc.main.Debug.v().showArgsMatching)
                System.out.println("args="+args+"sm="+sm+" of type "+sm.getClass());
        Residue ret=AlwaysMatch.v();
        ListIterator formalsIt=args.listIterator();
        List actuals=sm.getArgsContextValues();
        if(abc.main.Debug.v().showArgsMatching)
            System.out.println("actuals are "+actuals);
        ListIterator actualsIt=actuals.listIterator();
        int fillerpos=-1;
        while(formalsIt.hasNext() && actualsIt.hasNext()) {
            ArgPattern formal=(ArgPattern) formalsIt.next();
            if(abc.main.Debug.v().showArgsMatching)
                System.out.println("formal is "+formal);
            if(formal instanceof ArgFill) {
                if(abc.main.Debug.v().showArgsMatching)
                    System.out.println("filler at position "+(formalsIt.nextIndex()-1)
                                       +" ("+formal.getPosition()+")");
                fillerpos=formalsIt.nextIndex();  // The position _after_ the filler
                while(formalsIt.hasNext()) formalsIt.next();
                while(actualsIt.hasNext()) actualsIt.next();
                break;
            }
            ContextValue actual=(ContextValue) actualsIt.next();

            if(abc.main.Debug.v().showArgsMatching)
            	System.out.println("matching "+formal+" with "+actual);
            if (formal instanceof ArgVar) {
            	Var var = ((ArgVar) formal).getVar();
            	WeavingVar wvar = we.getWeavingVar(var);
//            	System.out.println("em ARGS: matching "+wvar.hashCode()+" with "+actual);
                MapValues.put(wvar, actual);
            }
            ret=AndResidue.construct(ret,formal.matchesAt(we,actual));

        }
        if(fillerpos==-1) {
            // we stopped because one list or the other ended,
            // and there were no ArgFills
            if(actualsIt.hasNext() ||
               (formalsIt.hasNext() &&
                // If there is one more formal left, it's ok as long as it is
                // an ArgFill. Note that we rely on the short-circuiting and
                // the left-to-right evaluation order
                // and that Iterator.next() affects the result of Iterator.hasNext()
                !(formalsIt.next() instanceof ArgFill && !formalsIt.hasNext())))
                return NeverMatch.v(); // the list lengths don't match up
            else return ret;
        }
        if(abc.main.Debug.v().showArgsMatching)
            System.out.println("actuals length is "+actuals.size()+" formals length is "+args.size());
        // There was an ArgFill
        if(actuals.size()<args.size()-1) // There aren't enough actuals for the formals minus the ArgFill
            return NeverMatch.v();

        while(formalsIt.hasPrevious() && actualsIt.hasPrevious()) {
            ArgPattern formal=(ArgPattern) formalsIt.previous();
            if(formal instanceof ArgFill) {
                /* this is now checked in the frontend:
                   if(formalsIt.nextIndex()+1!=fillerpos)
                   throw new SemanticException
                   ("Two fillers in args pattern",formal.getPosition());  */

                return ret; // all done!
            }
            ContextValue actual=(ContextValue) actualsIt.previous();

            if(abc.main.Debug.v().showArgsMatching)
                System.out.println("matching "+formal+" with "+actual);
            ret=AndResidue.construct(ret,formal.matchesAt(we,actual));
        }
        if(formalsIt.hasPrevious() && formalsIt.previous() instanceof ArgFill) return ret;
        // This shouldn't happen because we should find the filler before either the formals or the
        // actuals run out.
        throw new InternalCompilerError
            ("Internal error: reached the end of a args pattern list unexpectedly - "
             +"pattern was "+args+", method was "+method);
    }
}
